#![allow(non_snake_case, non_camel_case_types)]
use core::ffi;

use crate::{CachedID, JClassID, JEnv, JNameMaker, JPlainMarker};

pub struct JObject;

impl JObject {
	pub fn as_sys(&self) -> sys::jobject {
		self as *const JObject as *const ffi::c_void as *mut ffi::c_void as _
	}
	pub fn cast<T: JPlainMarker>(&self, env: &JEnv) -> Option<&T> {
		let from = self.class(env)?;
		let to = T::class(Some(env))?;
		if env.is_assignable(from, to) == Some(true) {
			unsafe { self.cast_unchecked() }
		} else {
			None
		}
	}
	pub unsafe fn cast_unchecked<T: JPlainMarker>(&self) -> Option<&T> {
		Some(unsafe { &*(self as *const Self as *const ffi::c_void as *const T) })
	}
	pub fn class(&self, env: &JEnv) -> Option<JClassID> {
		env.object_class(self.as_ref())
	}
}
impl JNameMaker for JObject {
	const JAVA_PATH: &'static [u8] = b"java/lang/Object\0";
}
impl JPlainMarker for JObject {
	fn class(env: Option<&JEnv>) -> Option<JClassID> {
		static CACHE: CachedID = CachedID::new();
		CACHE.get(|| JEnv::env(env)?.find_class(Self::JAVA_PATH))
	}
}
impl AsRef<JObject> for JObject {
	fn as_ref(&self) -> &JObject {
		self
	}
}
